﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Windows.Forms;
using Microsoft.VisualBasic.PowerPacks;
using Seagull.Configuration;
using Seagull.Controls;
using Seagull.DeployMarker.Properties;
using Seagull.Model;

namespace Seagull.DeployMarker
{
    public partial class MarkerForm : Form
    {
        private readonly Dictionary<OvalShape, ChannelInfo> _channels = new Dictionary<OvalShape, ChannelInfo>();
        private readonly ShapeContainer _shapeContainer;
        private Config _config;
        private string _configFileName;
        private Image _map;

        public MarkerForm()
        {
            var gmh = new GlobalMouseHandler();
            gmh.TheMouseMoved += OnMouseMoved;
            Application.AddMessageFilter(gmh);

            InitializeComponent();
            openFileDialog1.Filter = saveFileDialog1.Filter = "配置文件|*.xml|所有文件|*.*";
            _shapeContainer = new ShapeContainer { Parent = _picMap };
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            _map = Resources.gis_3D;
            ReloadMap();
        }

        private void ReloadMap()
        {
            _picMap.Image = _map;
            _picMap.Refresh();
        }

        private void OnMapMouseDown(object sender, MouseEventArgs e)
        {
            if(_config == null)
            {
                return;
            }
            var channelInfo = new ChannelInfo()
            {
                Name = string.Format("通道{0:D2}", _config.ChannelConfig.Channels.Count),
                WarningQuota1 = 60,
                WarningQuota2 = 234
            };
            if(EditChannelInfo(channelInfo))
            {
                var pointOnControl = new Point(e.X, e.Y);
                var pointOnMap = SetChannelPosition(channelInfo, pointOnControl);
                AddMarker(pointOnControl, channelInfo);
                _config.ChannelConfig.Channels.Add(channelInfo);
                Text = string.Format("{0}, {1}", pointOnMap.X, pointOnMap.Y);
            }
        }

        private Point SetChannelPosition(ChannelInfo channelInfo, Point pointOnControl)
        {
            var pointOnMap = MapHelper.ToPointOnMap(pointOnControl,
                new Point(_picMap.Width, _picMap.Height),
                new Point(_map.Width, _map.Height));
            channelInfo.X = pointOnMap.X;
            channelInfo.Y = pointOnMap.Y;
            return pointOnMap;
        }

        private bool EditChannelInfo(ChannelInfo channelInfo)
        {
            var propertyForm = new ChannelInfoForm { ChannelInfo = channelInfo };
            if(propertyForm.ShowDialog() == DialogResult.OK)
            {
                return true;
            }
            return false;
        }

        private void LoadConfig()
        {
            _config = Config.Load(_configFileName = openFileDialog1.FileName);
            ReloadMap();
            DrawMarkers(_config.ChannelConfig.Channels);
        }

        private void DrawMarkers(IEnumerable<ChannelInfo> channelPositions)
        {
            foreach(var channelPosition in channelPositions)
            {
                var pointOnControl = MapHelper.FromPointOnMap(
                    new Point(channelPosition.X, channelPosition.Y),
                    _shapeContainer.Size, _map.Size);
                AddMarker(pointOnControl, channelPosition);
            }
        }

        private void AddMarker(Point pointOnControl, ChannelInfo channelInfo)
        {
            var marker = MapHelper.DrawMarker(pointOnControl, _shapeContainer);
            marker.MouseDown += OnMarkerMouseDown;
            marker.MouseUp += OnMarkerMouseUp;
            marker.MouseEnter += (sender, e) =>
            {
                _channelNameToolStripStatusLabel.Text = channelInfo.Name;
            };
            marker.MouseLeave += (sender, e) =>
            {
                _channelNameToolStripStatusLabel.Text = string.Empty;
            };
            _channels.Add(marker, channelInfo);
            SelectMarker(marker);
        }

        private void editToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if(_selectedMarker != null)
            {
                EditChannelInfo(_channels[_selectedMarker]);
            }
        }

        private void deleteToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if(_selectedMarker != null && ConfirmDelete())
            {
                Config.Instance.ChannelConfig.Channels.Remove(_channels[_selectedMarker]);
                _channels.Remove(_selectedMarker);
                _shapeContainer.Shapes.Remove(_selectedMarker);
                _selectedMarker.Dispose();
                _selectedMarker = null;
            }
        }

        private bool ConfirmDelete()
        {
            return MessageBox.Show("确定要删除该通道吗？", "删除通道", MessageBoxButtons.YesNo) == DialogResult.Yes;
        }

        private void OnMarkerMoved(ChannelInfo channelInfo, Point positionOnControl)
        {
            SetChannelPosition(channelInfo, positionOnControl);
        }

        #region Marker Handle

        private Point _clickOffset;
        private bool _isDragging;
        private Point _lastCursorPosition;
        private OvalShape _selectedMarker;

        private void OnMarkerMouseUp(object sender, MouseEventArgs e)
        {
            Debug.WriteLine("Marker Mouse Up");
            _isDragging = false;
            if(_selectedMarker != null)
                OnMarkerMoved(_channels[_selectedMarker], GetCenterPosition(_selectedMarker));
        }

        private static Point GetCenterPosition(OvalShape marker)
        {
            return marker.Location +
                new Size(
                    (int)Math.Round(marker.Size.Width / 2.0),
                    (int)Math.Round(marker.Size.Height / 2.0));
        }

        private void OnMarkerMouseDown(object sender, MouseEventArgs e)
        {
            var marker = sender as OvalShape;
            if(marker != null)
            {
                SelectMarker(marker);

                if(e.Button == MouseButtons.Left)
                {
                    Debug.WriteLine("Marker Left Mouse Down");
                    _isDragging = true;
                    _lastCursorPosition = Cursor.Position;
                    _clickOffset.X = e.X;
                    _clickOffset.Y = e.Y;
                }
                else if(e.Button == MouseButtons.Right)
                {
                    _markerContextMenu.Show(this, PointToClient(Cursor.Position));
                }
            }
        }

        private void SelectMarker(OvalShape marker)
        {
            if(_selectedMarker != null)
            {
                _selectedMarker.FillColor = Color.White;
            }
            _selectedMarker = marker;
            _selectedMarker.FillColor = Color.Lime;
        }

        private void OnMouseMoved()
        {
            if(_selectedMarker != null && _isDragging)
            {
                var cursorPos = Cursor.Position;
                var delta = new Point(cursorPos.X - _lastCursorPosition.X,
                    cursorPos.Y - _lastCursorPosition.Y);
                _selectedMarker.Left = delta.X + _selectedMarker.Left;
                _selectedMarker.Top = delta.Y + _selectedMarker.Top;
                _lastCursorPosition = cursorPos;
            }
        }

        #endregion

        #region Toolbar buttons

        private void newToolStripButton_Click(object sender, EventArgs e)
        {
            _config = new Config();
            ReloadMap();
        }

        private void openToolStripButton_Click(object sender, EventArgs e)
        {
            if(openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                Config.SupressValidation = true;
                LoadConfig();
                Config.SupressValidation = false;
            }
        }

        private void saveToolStripButton_Click(object sender, EventArgs e)
        {
            try
            {
                _config.ChannelConfig.Validate();

                if(_configFileName == null)
                {
                    if(saveFileDialog1.ShowDialog() == DialogResult.OK)
                    {
                        _configFileName = saveFileDialog1.FileName;
                    }
                }
                _config.Save(_configFileName);
            }
            catch (Exception exception)
            {
                MessageBox.Show(exception.Message, "错误");
            }
        }

        #endregion
    }

    public delegate void MouseMovedEvent();

    public class GlobalMouseHandler : IMessageFilter
    {
        private const int WM_MOUSEMOVE = 0x0200;

        #region IMessageFilter Members

        public bool PreFilterMessage(ref Message m)
        {
            if(m.Msg == WM_MOUSEMOVE)
            {
                if(TheMouseMoved != null)
                {
                    TheMouseMoved();
                }
            }
            // Always allow message to continue to the next filter control
            return false;
        }

        #endregion

        public event MouseMovedEvent TheMouseMoved;
    }
}